﻿namespace Nop.Plugin.Payments.UsaEpay.Controllers
{
    #region

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Web.Mvc;

    using Nop.Core;
    using Nop.Plugin.Payments.UsaEpay.Models;
    using Nop.Services.Configuration;
    using Nop.Services.Localization;
    using Nop.Services.Payments;
    using Nop.Services.Stores;
    using Nop.Web.Framework.Controllers;

    #endregion

    /// <summary>
    /// The payment USA E-pay controller.
    /// </summary>
    public class PaymentUsaEpayController : BaseNopPaymentController
    {
        /// <summary>
        /// The localization service.
        /// </summary>
        private readonly ILocalizationService localizationService;

        /// <summary>
        /// The setting service.
        /// </summary>
        private readonly ISettingService settingService;

        /// <summary>
        /// The store service.
        /// </summary>
        private readonly IStoreService storeService;

        /// <summary>
        /// The work context.
        /// </summary>
        private readonly IWorkContext workContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="PaymentUsaEpayController"/> class.
        /// </summary>
        /// <param name="workContext">
        /// The work context.
        /// </param>
        /// <param name="storeService">
        /// The store service.
        /// </param>
        /// <param name="settingService">
        /// The setting service.
        /// </param>
        /// <param name="localizationService">
        /// The localization service.
        /// </param>
        public PaymentUsaEpayController(IWorkContext workContext, IStoreService storeService, ISettingService settingService, ILocalizationService localizationService)
        {
            this.workContext = workContext;
            this.storeService = storeService;
            this.settingService = settingService;
            this.localizationService = localizationService;
        }

        /// <summary>
        /// The validate payment form.
        /// </summary>
        /// <param name="form">
        /// The form.
        /// </param>
        /// <returns>
        /// The <see cref="IList{String}"/>.
        /// </returns>
        public override IList<string> ValidatePaymentForm(FormCollection form)
        {
            var warnings = new List<string>();

            // validate
            var validator = new PaymentInfoValidator(this.localizationService);
            var model = new PaymentInfoModel
                            {
                                CardholderName = form["CardholderName"], 
                                CardNumber = form["CardNumber"], 
                                CardCode = form["CardCode"], 
                                ExpireMonth = form["ExpireMonth"], 
                                ExpireYear = form["ExpireYear"]
                            };

            var validationResult = validator.Validate(model);
            if (!validationResult.IsValid)
            {
                warnings.AddRange(validationResult.Errors.Select(error => error.ErrorMessage));
            }

            return warnings;
        }

        /// <summary>
        /// The get payment info.
        /// </summary>
        /// <param name="form">
        /// The form.
        /// </param>
        /// <returns>
        /// The <see cref="ProcessPaymentRequest"/>.
        /// </returns>
        public override ProcessPaymentRequest GetPaymentInfo(FormCollection form)
        {
            var paymentInfo = new ProcessPaymentRequest
                                  {
                                      CreditCardType = form["CreditCardType"], 
                                      CreditCardName = form["CardholderName"], 
                                      CreditCardNumber = form["CardNumber"], 
                                      CreditCardExpireMonth = int.Parse(form["ExpireMonth"]), 
                                      CreditCardExpireYear = int.Parse(form["ExpireYear"]), 
                                      CreditCardCvv2 = form["CardCode"]
                                  };
            return paymentInfo;
        }

        /// <summary>
        /// The payment info.
        /// </summary>
        /// <returns>
        /// The <see cref="ActionResult"/>.
        /// </returns>
        [ChildActionOnly]
        public ActionResult PaymentInfo()
        {
            var model = new PaymentInfoModel();

            // CC types
            model.CreditCardTypes.Add(new SelectListItem { Text = "Visa", Value = "Visa", });
            model.CreditCardTypes.Add(new SelectListItem { Text = "Master card", Value = "MasterCard", });
            model.CreditCardTypes.Add(new SelectListItem { Text = "Discover", Value = "Discover", });
            model.CreditCardTypes.Add(new SelectListItem { Text = "Amex", Value = "Amex", });

            // years
            for (var i = 0; i < 15; i++)
            {
                var year = Convert.ToString(DateTime.Now.Year + i);
                model.ExpireYears.Add(new SelectListItem { Text = year, Value = year, });
            }

            // months
            for (var i = 1; i <= 12; i++)
            {
                var text = (i < 10) ? "0" + i : i.ToString(CultureInfo.InvariantCulture);
                model.ExpireMonths.Add(new SelectListItem { Text = text, Value = i.ToString(CultureInfo.InvariantCulture), });
            }

            // set postback values
            var form = this.Request.Form;
            model.CardholderName = form["CardholderName"];
            model.CardNumber = form["CardNumber"];
            model.CardCode = form["CardCode"];
            var selectedCcType = model.CreditCardTypes.FirstOrDefault(x => x.Value.Equals(form["CreditCardType"], StringComparison.InvariantCultureIgnoreCase));
            if (selectedCcType != null)
            {
                selectedCcType.Selected = true;
            }

            var selectedMonth = model.ExpireMonths.FirstOrDefault(x => x.Value.Equals(form["ExpireMonth"], StringComparison.InvariantCultureIgnoreCase));
            if (selectedMonth != null)
            {
                selectedMonth.Selected = true;
            }

            var selectedYear = model.ExpireYears.FirstOrDefault(x => x.Value.Equals(form["ExpireYear"], StringComparison.InvariantCultureIgnoreCase));
            if (selectedYear != null)
            {
                selectedYear.Selected = true;
            }

            return this.View("Nop.Plugin.Payments.UsaEpay.Views.PaymentUsaEpay.PaymentInfo", model);
        }

        /// <summary>
        ///     The configure.
        /// </summary>
        /// <returns>
        ///     The <see cref="ActionResult" />.
        /// </returns>
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            // load settings for a chosen store scope
            var storeScope = this.GetActiveStoreScopeConfiguration(this.storeService, this.workContext);
            var paymentMethodSettings = this.settingService.LoadSetting<UsaEpayPaymentSettings>(storeScope);
            var model = new ConfigureModel(paymentMethodSettings, storeScope);
            return this.View("Nop.Plugin.Payments.UsaEpay.Views.PaymentUsaEpay.Configure", model);
        }

        /// <summary>
        /// The configure.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="ActionResult"/>.
        /// </returns>
        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigureModel model)
        {
            if (!this.ModelState.IsValid)
            {
                return this.Configure();
            }

            // load settings for a chosen store scope
            var storeScope = this.GetActiveStoreScopeConfiguration(this.storeService, this.workContext);
            var paymentMethodSettings = this.settingService.LoadSetting<UsaEpayPaymentSettings>(storeScope);

            // save settings
            paymentMethodSettings.AdditionalFee = model.AdditionalFee;
            paymentMethodSettings.AdditionalFeePercentage = model.AdditionalFeePercentage;
            paymentMethodSettings.Pin = model.Pin;
            paymentMethodSettings.SourceKey = model.SourceKey;
            paymentMethodSettings.Url = model.Url;

            if (model.OverrideStoreAdditionalFee || storeScope == 0)
            {
                this.settingService.SaveSetting(paymentMethodSettings, x => x.AdditionalFee, storeScope, false);
            } 
            else if (storeScope > 0)
            {
                this.settingService.DeleteSetting(paymentMethodSettings, x => x.AdditionalFee, storeScope);
            }

            if (model.OverrideStoreAdditionalFeePercentage || storeScope == 0)
            {
                this.settingService.SaveSetting(paymentMethodSettings, x => x.AdditionalFeePercentage, storeScope, false);
            }
            else if (storeScope > 0)
            {
                this.settingService.DeleteSetting(paymentMethodSettings, x => x.AdditionalFeePercentage, storeScope);
            }

            if (model.OverrideStorePin || storeScope == 0)
            {
                this.settingService.SaveSetting(paymentMethodSettings, x => x.Pin, storeScope, false);
            }
            else if (storeScope > 0)
            {
                this.settingService.DeleteSetting(paymentMethodSettings, x => x.Pin, storeScope);
            }

            if (model.OverrideStoreSourceKey || storeScope == 0)
            {
                this.settingService.SaveSetting(paymentMethodSettings, x => x.SourceKey, storeScope, false);
            }
            else if (storeScope > 0)
            {
                this.settingService.DeleteSetting(paymentMethodSettings, x => x.SourceKey, storeScope);
            }

            if (model.OverrideStoreUrl || storeScope == 0)
            {
                this.settingService.SaveSetting(paymentMethodSettings, x => x.Url, storeScope, false);
            }
            else if (storeScope > 0)
            {
                this.settingService.DeleteSetting(paymentMethodSettings, x => x.Url, storeScope);
            }

            // now clear settings cache
            this.settingService.ClearCache();

            return this.Configure();
        }
    }
}